package org.ccay.manage.security.service.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;

import org.ccay.core.base.KeyValuePair;
import org.ccay.core.base.KeyValuePairVO;
import org.ccay.core.base.PageVO;
import org.ccay.core.base.PagedResult;
import org.ccay.manage.security.dao.IProgramDao;
import org.ccay.manage.security.service.IProgramManageService;
import org.ccay.security.authc.ProgramAuthorizationInfo;
import org.ccay.security.config.CurrentDimensionConfig;
import org.ccay.security.config.DimensionDefineConfig;
import org.ccay.security.config.SecurityConfig;
import org.ccay.security.entity.Program;
import org.ccay.security.vo.DimensionConfigVO;
import org.ccay.security.vo.ProgramItemsVO;
import org.ccay.security.vo.ProgramVO;

/**
 * 数据范围管理服务
 * @author chaowangbang
 *
 */
@Named
public class ProgramManageService implements IProgramManageService {
	/**
	 * 
	 */
	@Inject
	private IProgramDao programDao;
	
	@Override
	public PagedResult<ProgramVO> findPagedPrograms(ProgramVO programVO,
			PageVO page) {
		return programDao.findPagedPrograms(programVO,page);
	}
	
	@Override
	public List<DimensionConfigVO> findDimensionConfigs() {
		List<DimensionConfigVO> result = new ArrayList<DimensionConfigVO>();
		for(DimensionDefineConfig dc : SecurityConfig.getDimensionDefineConfigs()){
			DimensionConfigVO vo = new DimensionConfigVO();
			vo.setDimensionDisplayName(dc.getDimensionDisplayName());
			vo.setDimensionName(dc.getDimensionName());
			vo.setDataProviderBeanName(dc.getDataProviderBeanName());
			for(CurrentDimensionConfig cdc : SecurityConfig.getCurrentDimensionConfigs()){
				if(cdc.getDimensionName().equals(dc.getDimensionName())){
					vo.setCurrentDimension(true);
				}
			}
			result.add(vo);
		}
		return result;
	}

	@Override
	public PagedResult<KeyValuePair<? extends Serializable, String>> findPagedDimensionValues(
			String dimensionName,KeyValuePairVO condition, PageVO page) {
		for(DimensionDefineConfig dc : SecurityConfig.getDimensionDefineConfigs()){
			String key = condition.getKey();
			if(dimensionName.equals(dc.getDimensionName())){
				if(dc.getDimensionValueType().equals(Long.class)){
					KeyValuePair<Long,String> kvCondition = 
							new KeyValuePair<Long,String>(
									(null == key?null:Long.parseLong(key)),
									condition.getValue());
					return dc.getDataProvider().findPagedDimensionValues(kvCondition, page);
				}else if(dc.getDimensionValueType().equals(Integer.class)){
					KeyValuePair<Integer,String> kvCondition = 
							new KeyValuePair<Integer,String>(
									(null == key?null:Integer.parseInt(key)),
									condition.getValue());
					return dc.getDataProvider().findPagedDimensionValues(kvCondition, page);
				}else if(dc.getDimensionValueType().equals(String.class)){
					KeyValuePair<String,String> kvCondition = 
							new KeyValuePair<String,String>(key,condition.getValue());
					return dc.getDataProvider().findPagedDimensionValues(kvCondition, page);
				}
			}
		}
		return null;
	}

	@Override
	public List<KeyValuePair<? extends Serializable, String>> findDimensionValues(String dimensionName,List<String> keys) {
		for(DimensionDefineConfig dc : SecurityConfig.getDimensionDefineConfigs()){
			if(dimensionName.equals(dc.getDimensionName())){
				if(dc.getDimensionValueType().equals(Long.class)){
					List<Long> longIds = new ArrayList<Long>();
					for(String key:keys){
						longIds.add(Long.parseLong(key));
					}
					return dc.getDataProvider().findDimensionDisplayValues(longIds);
				}else if(dc.getDimensionValueType().equals(Integer.class)){
					List<Integer> intIds = new ArrayList<Integer>();
					for(String key:keys){
						intIds.add(Integer.parseInt(key));
					}
					return dc.getDataProvider().findDimensionDisplayValues(intIds);
				}else if(dc.getDimensionValueType().equals(String.class)){
					return dc.getDataProvider().findDimensionDisplayValues(keys);
				}
			}
		}
		return Collections.emptyList();
	}

	@Override
	public void createOrUpdateProgram(ProgramVO programVO) {
		if(programVO.getProgramId() == null ){//新建
			programDao.createProgram(programVO);
			
		}else{
			if(programVO.getProgramId().equals(ProgramAuthorizationInfo.PROGRAM_ALL_ID)){
				return ;//不能修改默认的全局数据范围
			}
			programDao.updateProgram(programVO);
		}
	}

	@Override
	public ProgramVO findProgram(Long programId) {
		ProgramVO result = programDao.findProgramById(programId);
		List<ProgramItemsVO> items = programDao.findProgramItemsByProgramId(programId);
		//组织ProgramItems的值
		Map<String,List<String>> values = new HashMap<String,List<String>>();
		for(ProgramItemsVO item : items){
			if(!values.containsKey(item.getDimension())){
				values.put(item.getDimension(), new ArrayList<String>());
			}
			List<String> valList = values.get(item.getDimension());
			valList.add(item.getValue());
		}
		//翻译
		for(Map.Entry<String,List<String>> entry : values.entrySet()){
			List<KeyValuePairVO> dimensionValues = new ArrayList<KeyValuePairVO>();
			if(entry.getValue().isEmpty()){
				continue;
			}
			//当前值处理
			if(entry.getValue().get(0).equals(Program.CURRENT_VALUE)){
				dimensionValues.add(new KeyValuePairVO(Program.CURRENT_VALUE, Program.CURRENT_VALUE));
			}else{
				//转换为KeyValuePairVO
				List<KeyValuePair<? extends Serializable, String>> kvPairs = findDimensionValues(entry.getKey(),entry.getValue());
				for(KeyValuePair<? extends Serializable, String> kv : kvPairs){
					dimensionValues.add(new KeyValuePairVO(kv.getKey().toString(),kv.getValue()));
				}
			}
			result.getDimensions().put(entry.getKey(), dimensionValues);
		}
		return result;
	}

	@Override
	public void deleteProgramCascade(Long programId) {
		if(programId.equals(ProgramAuthorizationInfo.PROGRAM_ALL_ID)){
			return ;
		}
		//删除Program 并删除此Program下的权限
		programDao.deleteProgramCascade(programId);
	}

	@Override
	public Boolean checkProgramNameUnique(String programName, Long programId) {
		return programDao.checkProgramNameUnique(programName,programId)==0;
	}
	
	@Override
	public Boolean checkReferenced(Long programId) {
		return programDao.checkReferenced(programId) > 0;
	}
}
